import os


def walk_file(path, ext=None, not_in=None, is_in=None, get_full_paths=True, deep=True):
    """
    列出文件夹中的文件, 并根据后缀、关键字筛选出来
    注意：若get_full_paths为False时，可能得到重复的文件名
    :param path: 根目录
    :param ext: 需要的文件的后缀名,可为单个后缀，或后缀列表。例如：'exe'或['exe', 'txt']
    :param not_in: 文件名中不能包含的字符。例如：'~$'或['~$', 'tmp']
    :param is_in: 文件名中必须包含的字符。例如：'abc'或['abc', 'def']
    :param get_full_paths: 默认True时返回文件的完整路径列表，否则返回文件名列表
    :param deep: 默认True，表示深度遍历所有子文件夹下的文件；若为False，只获取当前目录path下的文件
    :return: [files] or [file_paths]
    """
    # 检查给定路径是否为目录，如果不是则返回None
    if not os.path.isdir(path):
        return None

    # 参数规范化函数，将参数转换为小写列表
    def normalize_param(param):
        if param is None:
            return None
        if not isinstance(param, list):
            return [param.lower()]
        return [x.lower() for x in param]

    # 规范化处理ext，not_in，is_in参数
    ext = normalize_param(ext)
    not_in = normalize_param(not_in)
    is_in = normalize_param(is_in)

    # 初始化文件列表
    filelist = []

    # 根据deep参数决定是否深度遍历
    if not deep:
        # 只遍历当前目录
        for file in os.listdir(path):
            one_file_path = os.path.join(path, file)
            file_name = os.path.basename(one_file_path)
            f_ext = os.path.splitext(file_name)[1].lower()

            # 根据文件后缀，not_in，is_in筛选文件
            if ext is None or f_ext[1:] in ext:
                if not_in is None or all(ni not in file_name for ni in not_in):
                    if is_in is None or any(ii in file_name for ii in is_in):
                        # 根据get_full_paths参数决定添加文件的完整路径还是文件名
                        if get_full_paths:
                            filelist.append(os.path.abspath(one_file_path))
                        else:
                            filelist.append(file)
    else:
        # 深度遍历
        for root, _, files in os.walk(path):
            for file in files:
                one_file_path = os.path.join(root, file)
                file_name = os.path.basename(one_file_path)
                f_ext = os.path.splitext(file_name)[1].lower()
                # 同样的筛选逻辑
                if ext is None or f_ext[1:] in ext:
                    if not_in is None or all(ni not in file_name for ni in not_in):
                        if is_in is None or any(ii in file_name for ii in is_in):
                            # 根据get_full_paths参数决定添加文件的完整路径还是文件名
                            if get_full_paths:
                                filelist.append(os.path.abspath(one_file_path))
                            else:
                                filelist.append(file)
    # 返回文件列表
    return filelist



def replace_in_file(file_path, source_text, target_text):
    """在指定文件中将source_text替换为target_text"""
    with open(file_path, 'r', encoding='utf-8') as file:
        content = file.read()

    # 替换文本
    new_content = content.replace(source_text, target_text)

    # 如果内容有变化，则写回文件
    if new_content != content:
        with open(file_path, 'w', encoding='utf-8') as file:
            file.write(new_content)
        return file_path
    return None


def replace_file_name(file_path, new_path):
    os.rename(file_path, new_path)


class ReplaceTool:
    def __init__(self):
        self.project_dir = ''
        self.old_str = ''
        self.new_str = ''
        self.file_name = True

    def deal_params(self, ui_data):
        self.project_dir = ui_data.get('project_dir')
        self.old_str = ui_data.get('old_str')
        self.new_str = ui_data.get('new_str')
        self.file_name = ui_data.get('file_name')

    def replace(self, data):
        self.deal_params(data)
        old_file_list = walk_file(self.project_dir, 'py')
        rename_file_list = []
        content_change_file_list = []
        actual_file_list = []
        if self.file_name:
            for file in old_file_list:
                new_file_name = file.replace(self.old_str, self.new_str)
                actual_file_list.append(new_file_name)
                if new_file_name != file:
                    replace_file_name(file, new_file_name)
                    rename_file_list.append(file)
        else:
            actual_file_list = old_file_list
        for file in actual_file_list:
            res = replace_in_file(file, self.old_str, self.new_str)
            if isinstance(res, str):
                content_change_file_list.append(res)
        return rename_file_list, content_change_file_list